home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2005 October / PCWOCT05.iso / Software / FromTheMag / XAMPP 1.4.14 / xampp-win32-1.4.14-installer.exe / xampp / php / pear / FSM.php < prev    next >
PHP Script  |  2004-03-24  |  10KB  |  284 lines

  1. <?php
  2. /* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */
  3. /* +----------------------------------------------------------------------+
  4.  * | PHP Version 4                                                        |
  5.  * +----------------------------------------------------------------------+
  6.  * | Copyright (c) 1997-2003 The PHP Group                                |
  7.  * +----------------------------------------------------------------------+
  8.  * | This source file is subject to version 2.02 of the PHP license,      |
  9.  * | that is bundled with this package in the file LICENSE, and is        |
  10.  * | available at through the world-wide-web at                           |
  11.  * | http://www.php.net/license/2_02.txt.                                 |
  12.  * | If you did not receive a copy of the PHP license and are unable to   |
  13.  * | obtain it through the world-wide-web, please send a note to          |
  14.  * | license@php.net so we can mail you a copy immediately.               |
  15.  * +----------------------------------------------------------------------+
  16.  * | Authors: Jon Parise <jon@php.net>                                    |
  17.  * +----------------------------------------------------------------------+
  18.  *
  19.  * $Id: FSM.php,v 1.8 2003/10/03 07:52:11 jon Exp $
  20.  */
  21.  
  22. /**
  23.  * This class implements a Finite State Machine (FSM).
  24.  *
  25.  * In addition to maintaining state, this FSM also maintains a user-defined
  26.  * payload, therefore effectively making the machine a Push-Down Automata
  27.  * (a finite state machine with memory).
  28.  *
  29.  * @author  Jon Parise <jon@php.net>
  30.  * @version $Revision: 1.8 $
  31.  * @package FSM
  32.  */
  33. class FSM
  34. {
  35.     /**
  36.      * Represents the initial state of the machine.
  37.      *
  38.      * @var string
  39.      * @see $_currentState
  40.      * @access private
  41.      */
  42.     var $_initialState = '';
  43.  
  44.     /**
  45.      * Contains the current state of the machine.
  46.      *
  47.      * @var string
  48.      * @see $_initialState
  49.      * @access private
  50.      */
  51.     var $_currentState = '';
  52.  
  53.     /**
  54.      * Contains the payload that will be passed to each action function.
  55.      *
  56.      * @var mixed
  57.      * @access private
  58.      */
  59.     var $_payload = null;
  60.  
  61.     /**
  62.      * Maps (inputSymbol, currentState) --> (action, nextState).
  63.      *
  64.      * @var array
  65.      * @see $_inputState, $_currentState
  66.      * @access private
  67.      */
  68.     var $_transitions = array();
  69.  
  70.     /**
  71.      * Maps (currentState) --> (action, nextState).
  72.      *
  73.      * @var array
  74.      * @see $_inputState, $_currentState
  75.      * @access private
  76.      */
  77.     var $_transitionsAny = array();
  78.  
  79.     /**
  80.      * Contains the default transition that is used if no more appropriate
  81.      * transition has been defined.
  82.      *
  83.      * @var array
  84.      * @access private
  85.      */
  86.     var $_defaultTransition = null;
  87.  
  88.  
  89.     /**
  90.      * This method constructs a new Finite State Machine (FSM) object.  In
  91.      * addition to defining the machine's initial state, a "payload" may also
  92.      * be specified.  The payload represents a variable that will be passed
  93.      * along to each of the action functions.  If the FSM is being used for
  94.      * parsing, the payload is often a array that is used as a stack.
  95.      *
  96.      * @param   string  $initialState   The initial state of the FSM.
  97.      * @param   mixed   $payload        A payload that will be passed to each
  98.      *                                  action function.
  99.      */
  100.     function FSM($initialState, &$payload)
  101.     {
  102.         $this->_initialState = $initialState;
  103.         $this->_currentState = $initialState;
  104.         $this->_payload = &$payload;
  105.     }
  106.  
  107.     /**
  108.      * This method resets the FSM by setting the current state back to the
  109.      * initial state (set by the constructor).  The current input symbol is
  110.      * also reset to NULL.
  111.      */
  112.     function reset()
  113.     {
  114.         $this->_currentState = $this->_initialState;
  115.         $this->_inputSymbol = null;
  116.     }
  117.  
  118.     /**
  119.      * This method adds a new transition that associates:
  120.      *
  121.      *      (symbol, currentState) --> (nextState, action)
  122.      *
  123.      * The action may be set to NULL, in which case the processing routine
  124.      * will ignore the action and just set the next state.
  125.      *
  126.      * @param   string  $symbol         The input symbol.
  127.      * @param   string  $state          This transition's starting state.
  128.      * @param   string  $nextState      This transition's ending state.
  129.      * @param   string  $action         The name of the function to invoke
  130.      *                                  when this transition occurs.
  131.      *
  132.      * @see     addTransitions()
  133.      */
  134.     function addTransition($symbol, $state, $nextState, $action = null)
  135.     {
  136.         $this->_transitions["$symbol,$state"] = array($nextState, $action);
  137.     }
  138.  
  139.     /**
  140.      * This method adds the same transition for multiple different symbols.
  141.      *
  142.      * @param   array   $symbols        A list of input symbols.
  143.      * @param   string  $state          This transition's starting state.
  144.      * @param   string  $nextState      This transition's ending state.
  145.      * @param   string  $action         The name of the function to invoke
  146.      *                                  when this transition occurs.
  147.      *
  148.      * @see     addTransition()
  149.      */
  150.     function addTransitions($symbols, $state, $nextState, $action = null)
  151.     {
  152.         foreach ($symbols as $symbol) {
  153.             $this->addTransition($symbol, $state, $nextState, $action);
  154.         }
  155.     }
  156.  
  157.     /**
  158.      * This method adds a new transition that associates:
  159.      *
  160.      *      (currentState) --> (nextState, action)
  161.      *
  162.      * The processing routine checks these associations if it cannot first
  163.      * find a match for (symbol, currentState).
  164.      *
  165.      * @param   string  $state          This transition's starting state.
  166.      * @param   string  $nextState      This transition's ending state.
  167.      * @param   string  $action         The name of the function to invoke
  168.      *                                  when this transition occurs.
  169.      *
  170.      * @see     addTransition()
  171.      */
  172.     function addTransitionAny($state, $nextState, $action = null)
  173.     {
  174.         $this->_transitionsAny[$state] = array($nextState, $action);
  175.     }
  176.  
  177.     /**
  178.      * This method sets the default transition.  This defines an action and
  179.      * next state that will be used if the processing routine cannot find a
  180.      * suitable match in either transition list.  This is useful for catching
  181.      * errors caused by undefined states.
  182.      *
  183.      * The default transition can be removed by setting $nextState to NULL.
  184.      *
  185.      * @param   string  $nextState      The transition's ending state.
  186.      * @param   string  $action         The name of the function to invoke
  187.      *                                  when this transition occurs.
  188.      */
  189.     function setDefaultTransition($nextState, $action)
  190.     {
  191.         if (empty($nextState)) {
  192.             $this->_defaultTransition = null;
  193.             return;
  194.         }
  195.  
  196.         $this->_defaultTransition = array($nextState, $action);
  197.     }
  198.  
  199.     /**
  200.      * This method returns (nextState, action) given an input symbol and
  201.      * state.  The FSM is not modified in any way.  This method is rarely
  202.      * called directly (generally only for informational purposes).
  203.      *
  204.      * If the transition cannot be found in either of the transitions lists,
  205.      * the default transition will be returned.  Note that it is possible for
  206.      * the default transition to be set to NULL.
  207.      *
  208.      * @param   string  $symbol         The input symbol.
  209.      *
  210.      * @return  mixed   Array representing (nextState, action), or NULL if the
  211.      *                  transition could not be found and not default
  212.      *                  transition has been defined.
  213.      */
  214.     function getTransition($symbol)
  215.     {
  216.         $state = $this->_currentState;
  217.  
  218.         if (array_key_exists("$symbol,$state", $this->_transitions)) {
  219.             return $this->_transitions["$symbol,$state"];
  220.         } elseif (array_key_exists($state, $this->_transitionsAny)) {
  221.             return $this->_transitionsAny[$state];
  222.         } else {
  223.             return $this->_defaultTransition;
  224.         }
  225.     }
  226.  
  227.     /**
  228.      * This method is the main processing routine.  It causes the FSM to
  229.      * change states and execute actions.
  230.      *
  231.      * The transition is determined by calling getTransition() with the
  232.      * provided symbol and the current state.  If no valid transition is found,
  233.      * process() returns immediately.
  234.      *
  235.      * The action callback may return the name of a new state.  If one is
  236.      * returned, the current state will be updated to the new value.
  237.      *
  238.      * If no action is defined for the transition, only the state will be
  239.      * changed.
  240.      *
  241.      * @param   string  $symbol         The input symbol.
  242.      *
  243.      * @see     processList()
  244.      */
  245.     function process($symbol)
  246.     {
  247.         $transition = $this->getTransition($symbol);
  248.  
  249.         /* If a valid array wasn't returned, return immediately. */
  250.         if (!is_array($transition) || (count($transition) != 2)) {
  251.             return;
  252.         }
  253.  
  254.         /* Update the current state to this transition's exit state. */
  255.         $this->_currentState = $transition[0];
  256.  
  257.         /* If an action for this transition has been specified, execute it. */
  258.         if (!empty($transition[1])) {
  259.             $state = call_user_func_array($transition[1],
  260.                                           array($symbol, &$this->_payload));
  261.  
  262.             /* If a new state was returned, update the current state. */
  263.             if (!empty($state) && is_string($state)) {
  264.                 $this->_currentState = $state;
  265.             }
  266.         }
  267.     }
  268.  
  269.     /**
  270.      * This method processes a list of symbols.  Each symbol in the list is
  271.      * sent to process().
  272.      *
  273.      * @param   array   $symbols        List of input symbols to process.
  274.      */
  275.     function processList($symbols)
  276.     {
  277.         foreach ($symbols as $symbol) {
  278.             $this->process($symbol);
  279.         }
  280.     }
  281. }
  282.  
  283. ?>
  284.